<template>
  <div class="audio-player">
    <div ref="waveSurferRef" class="waveView"></div>
    <div ref="timelineRef" />
  </div>
  <input type="file" accept="audio/*" @change="handleFileChange" />
  <button @click="play">播放</button>
  <button @click="pause">暂停</button>
  <button @click="stop">停止</button>
</template>

<script lang="ts" setup>
import { onMounted, onUnmounted, ref,defineEmits } from "vue";

const emit = defineEmits(['on-play','on-pause','on-finish','on-timeupdate'])

import WaveSurfer from "wavesurfer.js"
import Spectrogram from "wavesurfer.js/dist/plugins/spectrogram.esm.js";
import TimelinePlugin from "wavesurfer.js/dist/plugins/timeline.esm.js";
import ZoomPlugin from 'wavesurfer.js/dist/plugins/zoom.esm.js'
import RegionsPlugin from 'wavesurfer.js/dist/plugins/regions.esm.js'
import Hover from 'wavesurfer.js/dist/plugins/hover.esm.js'

// import Regions from 'wavesurfer.js/dist/plugins/regions.js'

// 初始化 Wavesurfer 实例
const waveSurfer = ref<WaveSurfer>();

const waveSurferRef = ref<HTMLDivElement | null>(null);

// 定义加载 Wav 数据的方法
const loadAudioDataWAVE = (arrayBuffer: ArrayBuffer) => {
  if (waveSurfer.value) {
    waveSurfer.value.loadBlob(new Blob([arrayBuffer], { type: "audio/wav" }));
  }
};

// 定义加载 Wav 数据的方法
const loadAudioDataMP3 = (arrayBuffer: ArrayBuffer) => {
  if (waveSurfer.value) {
    waveSurfer.value.loadBlob(new Blob([arrayBuffer], { type: "audio/mp3" }));
  }
};


// 定义加载PCM 数据的方法
const loadAudioDataPCM = (pcmArrayBuffer: ArrayBuffer, sampleRate: number, bitDepth: number, numChannels: number) => {
  console.log("加载PCM数据");
  // 计算数据大小
  const dataSize = pcmArrayBuffer.byteLength;
  // 创建WAV头部
  const wavHeader = createWavHeader(sampleRate, bitDepth, numChannels, dataSize);

  // 合并头部和PCM数据
  const combinedBuffer = new Uint8Array(wavHeader.byteLength + dataSize);
  combinedBuffer.set(new Uint8Array(wavHeader), 0);
  combinedBuffer.set(new Uint8Array(pcmArrayBuffer), wavHeader.byteLength);
  if (waveSurfer.value) {
    waveSurfer.value.loadBlob(new Blob([combinedBuffer], { type: "audio/wav" }));
  }
};

const toTimePlay = (time: number) =>{
  waveSurfer.value?.setTime(time);
  waveSurfer.value?.play();
}
// 创建WAV头部
function createWavHeader(sampleRate: number, bitDepth: number, numChannels: number, dataSize: number) {
  const headerLength = 44;
  const fileLength = headerLength + dataSize;
  const buffer = new ArrayBuffer(headerLength);
  const view = new DataView(buffer);

  // RIFF chunk descriptor
  writeString(view, 0, 'RIFF');
  view.setUint32(4, fileLength - 8, true);  // File size (not including 8 byte riff chunk descriptor)
  writeString(view, 8, 'WAVE');

  // Format sub-chunk
  writeString(view, 12, 'fmt ');
  view.setUint32(16, 16, true);  // Size of format chunk
  view.setUint16(20, 1, true);   // Audio format (1 for PCM)
  view.setUint16(22, numChannels, true);  // Number of channels
  view.setUint32(24, sampleRate, true);  // Sample rate
  view.setUint32(28, sampleRate * numChannels * (bitDepth / 8), true);  // Byte rate
  view.setUint16(32, numChannels * (bitDepth / 8), true);  // Block align
  view.setUint16(34, bitDepth, true);  // Bits per sample

  // Data sub-chunk
  writeString(view, 36, 'data');
  view.setUint32(40, dataSize, true);  // Subchunk2 size

  return view.buffer;
}

function writeString(view: DataView, offset: number, str: string) {
  for (let i = 0; i < str.length; i++) {
    view.setUint8(offset + i, str.charCodeAt(i));
  }
}

//处理文件输入的方法
const handleFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  if (file) {
    const reader = new FileReader();
    reader.onload = (e) => {
      const arrayBuffer = e.target?.result as ArrayBuffer;
      loadAudioDataWAVE(arrayBuffer);
    };
    reader.readAsArrayBuffer(file);
  }
};

const regions = RegionsPlugin.create()

// 在组件挂载时初始化 Wavesurfer
onMounted(() => {
  waveSurfer.value = WaveSurfer.create({
    container: waveSurferRef.value!,
    waveColor: "#FF55C5", //光标后波形的填充颜色。
    progressColor: "#00BFBF", //光标后面部分波形的填充颜色。当progressColor和waveColor相同时，进度波根本不会被渲染。
    cursorColor: "yellow", //指针的填充颜色，表示播放头位置。
    height: 100, //波形的高度。以像素为单位。
    audioRate: 1, //播放音频的速度。数值越低，速度越慢。
    barGap: 0, //波条之间的可选间距，如果没有提供，将以遗留格式计算。
    barHeight: 0, //波形条的高度。大于1的数字将增加波形条的高度。
    barRadius: 0, //使bars变圆的半径
    barWidth: 0, //如果指定，波形将像这样绘制▁ ▂ ▇ ▃ ▅ ▂
    fillParent: true, //是否填充整个容器或仅根据minPxPerSec绘制。
    minPxPerSec: 1, //音频每秒的最小像素数。
    hideScrollbar: true, //是否在通常显示水平滚动条时隐藏水平滚动条。
    interact: true, //是否在初始化时启用鼠标交互。您可以在以后的任何时候切换该参数。
    normalize: true, //如果为真，则通过最大峰值而不是1.0进行归一化。
    plugins: [
      Spectrogram.create({
        // waveColor: "violet",
        // progressColor: "purple",
        height: 100,
        fftSamples: 1024,
        windowFunc: "blackman",
        splitChannels: true,
      }),
      TimelinePlugin.create({
        height: 20, // - 时间线的高度（以像素为单位）。默认值为 20.
        style: "border:5px",
        // notchPercentHeight: 80, // - 时间线中次要缺口线的高度（以百分比表示）。默认值为 90。
        // primaryColor: "#f00", //- 模十凹口线的颜色（例如 10 秒、20 秒）。默认值为“#000”。
        // secondaryColor: "#ccc", //- 非模十凹口线的颜色. 默认值为'#c0c0c0'.
        // insertPosition:true,//将时间轴插入到波形的顶部
        // duration:10,//时间轴的持续时间(以秒为单位)，默认为波形发生器的持续时间
        // timeInterval:1,// 节拍间隔，单位为秒
        // primaryLabelSpacing:2,//数字标签之间的间隔
        // secondaryLabelSpacing:2,//二级数字标签之间的间隔
        primaryLabelInterval: 1, // 数字标签之间的间隔(以秒为单位)
        secondaryLabelInterval: 1, // 辅助数字标签之间的间隔(以秒为单位)
        // offset: 10, //- 时间轴开始的偏移量（以秒为单位）。该值也可能为负数，默认为 0.
        // labels: true,
        formatTimeCallback: (time: number) => {
          return formatTime(time);
        }, //- 自定义时间格式回调。 （接收秒数并返回格式化字符串的函数）
      }), Hover.create({
        lineColor: '#ff0000',
        lineWidth: 2,
        labelBackground: '#555',
        labelColor: '#fff',
        labelSize: '11px',
      }),
      ZoomPlugin.create({
        // the amount of zoom per wheel step, e.g. 0.5 means a 50% magnification per scroll
        scale: 0.5,
        // Optionally, specify the maximum pixels-per-second factor while zooming
        maxZoom: 1000,
      }),
      regions,
      
      // Hover.create({
      //     showTime: true,  //是否显示时间
      //     opacity: 1,  //光标及时间整个组件的透明度
      //     customShowTimeStyle: {  //时间展示的设置
      //         'background-color': '#000',  //时间展示块的背景色
      //         color: '#fff',  //时间展示文字的颜色
      //         padding: '2px',  //时间展示块的padding
      //         'font-size': '10px'  //时间展示文字的font-size
      //     }
      // }),
    ],
  });

  const random = (min, max) => Math.random() * (max - min) + min
  const randomColor = () => `rgba(${random(0, 255)}, ${random(0, 255)}, ${random(0, 255)}, 0.5)`
  let loop = true
  let activeRegion = null
  regions.on('region-in', (region) => {
    console.log('region-in', region)
    activeRegion = region
  })
  regions.on('region-out', (region) => {
    console.log('region-out', region)
    if (activeRegion === region) {
      if (loop) {
        region.play()
      } else {
        activeRegion = null
      }
    }
  })
  regions.on('region-clicked', (region, e) => {
    e.stopPropagation() // prevent triggering a click on the waveform
    activeRegion = region
    region.play()
    region.setOptions({ color: randomColor() })
  })
  regions.on('region-double-clicked', (region, e) => {
    e.stopPropagation() // prevent triggering a click on the waveform
    activeRegion = region
    region.remove();
    waveSurfer.value?.stop();
  })
  // 加载音频文件
  waveSurfer.value.load('path/to/your/audio/file.mp3');
  regions.enableDragSelection({
    color: 'rgba(255, 0, 0, 0.1)',
  })

  // 设置播放回调
  waveSurfer.value.on('play', () => {
    emit("on-play")
  });

  waveSurfer.value.on('pause', () => {
    emit("on-pause")
  });

  waveSurfer.value.on('finish', () => {
    emit("on-finish")
  });

  waveSurfer.value.on('timeupdate', (time: number) => {
    emit("on-timeupdate",time)
  });
  // Initialize the Zoom plugin
  
});

// 在组件卸载时销毁 Wavesurfer 实例
onUnmounted(() => {
  if (waveSurfer.value) {
    waveSurfer.value.destroy();
  }
});

// 定义播放、暂停和停止的方法
const play = () => {
  if (waveSurfer.value) {
    waveSurfer.value.play();
  }
};

const pause = () => {
  if (waveSurfer.value) {
    waveSurfer.value.pause();
  }
};

const stop = () => {
  if (waveSurfer.value) {
    waveSurfer.value.stop();
    regions.clearRegions();
    
  }
};
// 格式化时间
const formatTime = (time: number) => {
  const minutes = Math.floor(time / 60);
  const seconds = Math.floor(time % 60);
  return `${pad(minutes)}:${pad(seconds)}`;
};

// 补零
const pad = (num: number) => {
  return num.toString().padStart(2, "0");
};

defineExpose({ loadAudioDataWAVE, loadAudioDataPCM, loadAudioDataMP3,toTimePlay });
</script>

<style scoped>
.audio-player {
  display: flex;
  /* justify-content: center; */
  /* align-items: center; */
  height: 100%;
  /* flex-direction: column; */
}

button {
  margin-right: 10px;
}

.waveView {
  width: 100%;
  height: 240px;
}
</style>
